package com.decompiler;

import org.apache.commons.io.FileUtils;
import org.benf.cfr.reader.api.CfrDriver;
import org.benf.cfr.reader.api.OutputSinkFactory;
import org.benf.cfr.reader.api.SinkReturns;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;

/**
 * JAR包反编译器类
 * 负责JAR文件的反编译和代码导出功能
 * 优化了反编译效率，使用并行处理和缓存机制
 */
public class JarDecompiler {
    // 使用ConcurrentHashMap提高并发性能
    private final Map<String, String> decompiledCodeMap = new ConcurrentHashMap<>();
    private final Map<String, JavaElementType> elementTypeMap = new ConcurrentHashMap<>();
    private final Map<String, String> nonJavaFilesMap = new ConcurrentHashMap<>(); // 存储非Java文件的内容
    
    // 添加反编译缓存，避免重复反编译相同的类
    private final Map<String, String> decompileCache = new ConcurrentHashMap<>();
    
    // 线程池用于管理并行任务
    private final ExecutorService executorService;
    
    private File tempDir;
    private File jarFile;
    
    /**
     * 构造函数，初始化线程池
     */
    public JarDecompiler() {
        // 创建线程池，线程数为可用处理器数量（但最多4个线程）
        int processors = Math.min(Runtime.getRuntime().availableProcessors(), 4);
        executorService = Executors.newFixedThreadPool(processors);
    }
    
    /**
     * 反编译JAR文件
     * 优化了资源管理和异常处理
     * @param jarFile JAR文件
     * @return 反编译是否成功
     */
    public boolean decompileJar(File jarFile) {
        this.jarFile = jarFile;
        decompiledCodeMap.clear();
        elementTypeMap.clear();
        nonJavaFilesMap.clear();
        // 保留缓存，不清除decompileCache，以便在多次反编译时重用
        
        try {
            // 创建临时目录用于解压JAR文件
            if (tempDir != null && tempDir.exists()) {
                try {
                    FileUtils.deleteDirectory(tempDir);
                } catch (IOException e) {
                    System.err.println("Warning: Failed to delete previous temp directory: " + e.getMessage());
                }
            }
            
            tempDir = Files.createTempDirectory("jar_decompiler_temp").toFile();
            tempDir.deleteOnExit();
            
            // 解压JAR文件到临时目录
            long startTime = System.currentTimeMillis();
            extractJar(jarFile, tempDir);
            long extractTime = System.currentTimeMillis() - startTime;
            System.out.println("JAR extraction completed in " + extractTime + "ms");
            
            // 使用CFR反编译所有class文件
            startTime = System.currentTimeMillis();
            decompileClasses(tempDir);
            long decompileTime = System.currentTimeMillis() - startTime;
            System.out.println("Decompilation completed in " + decompileTime + "ms");
            
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            // 清理资源
            if (tempDir != null && tempDir.exists()) {
                try {
                    FileUtils.deleteDirectory(tempDir);
                } catch (IOException ex) {
                    // 忽略清理过程中的错误
                }
            }
            return false;
        }
    }
    
    /**
     * 关闭反编译器并释放资源
     * 应在应用程序关闭时调用
     */
    public void close() {
        // 关闭线程池
        if (executorService != null && !executorService.isShutdown()) {
            executorService.shutdown();
            try {
                // 等待所有任务完成
                if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) {
                    executorService.shutdownNow();
                }
            } catch (InterruptedException e) {
                executorService.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
        
        // 清理临时目录
        if (tempDir != null && tempDir.exists()) {
            try {
                FileUtils.deleteDirectory(tempDir);
            } catch (IOException e) {
                System.err.println("Warning: Failed to delete temp directory: " + e.getMessage());
            }
        }
    }
    
    /**
     * 获取反编译后的所有类名
     * @return 类名集合
     */
    public Set<String> getDecompiledClasses() {
        return decompiledCodeMap.keySet();
    }
    
    /**
     * 获取指定类的元素类型（类、接口或枚举）
     * @param className 类名
     * @return 元素类型
     */
    public JavaElementType getElementType(String className) {
        return elementTypeMap.getOrDefault(className, JavaElementType.UNKNOWN);
    }
    
    /**
     * 获取指定类的反编译代码
     * @param className 类名
     * @return 反编译后的代码
     */
    public String getDecompiledCode(String className) {
        return decompiledCodeMap.get(className);
    }
    
    /**
     * 获取非Java文件的内容
     * @param fileName 文件名
     * @return 文件内容
     */
    public String getNonJavaFileContent(String fileName) {
        return nonJavaFilesMap.get(fileName);
    }
    
    /**
     * 获取所有非Java文件的名称
     * @return 非Java文件名集合
     */
    public Set<String> getNonJavaFiles() {
        return nonJavaFilesMap.keySet();
    }
    
    /**
     * 获取非Java文件的数量
     * @return 非Java文件数量
     */
    public int getNonJavaFilesCount() {
        return nonJavaFilesMap.size();
    }
    
    /**
     * 导出反编译后的代码到指定目录
     * 使用自定义线程池和NIO优化导出效率
     * @param exportDir 导出目录
     * @return 导出是否成功
     */
    public boolean exportDecompiledCode(File exportDir) {
        try {
            if (!exportDir.exists()) {
                exportDir.mkdirs();
            }
            
            // 获取JAR文件名作为导出目录名（不包含扩展名和版本号）
            String jarName = jarFile.getName();
            if (jarName.toLowerCase().endsWith(".jar")) {
                jarName = jarName.substring(0, jarName.length() - 4);
            }
            
            // 移除版本号（通常格式为：name-x.y.z）
            int versionSeparatorIndex = jarName.indexOf('-');
            if (versionSeparatorIndex > 0) {
                // 检查是否是版本号分隔符
                boolean isVersionNumber = false;
                if (versionSeparatorIndex + 1 < jarName.length()) {
                    char nextChar = jarName.charAt(versionSeparatorIndex + 1);
                    isVersionNumber = Character.isDigit(nextChar);
                }
                
                if (isVersionNumber) {
                    jarName = jarName.substring(0, versionSeparatorIndex);
                }
            }
            
            // 创建以JAR包名命名的导出目录
            final File jarExportDir = new File(exportDir, jarName);
            if (!jarExportDir.exists()) {
                jarExportDir.mkdirs();
            }
            
            // 创建目录缓存，避免重复创建目录，预分配容量
            Set<String> createdDirs = Collections.synchronizedSet(new HashSet<>(128));
            
            // 使用计数器跟踪完成的任务数量
            final CountDownLatch javaFilesLatch = new CountDownLatch(decompiledCodeMap.size());
            final CountDownLatch resourceFilesLatch = new CountDownLatch(nonJavaFilesMap.size());
            
            // 创建异常引用，用于捕获并行处理中的异常
            final AtomicReference<Exception> exportException = new AtomicReference<>();
            
            // 使用自定义ForkJoinPool控制并行度，避免过度并行
            int parallelism = Math.min(Runtime.getRuntime().availableProcessors(), 8);
            ForkJoinPool customThreadPool = new ForkJoinPool(parallelism);
            
            try {
                // 使用自定义线程池执行并行任务
                customThreadPool.submit(() -> {
                    // 预创建常用目录结构，减少同步开销
                    String baseJavaPath = new File(jarExportDir, "src" + File.separator + "main" + File.separator + "java").getAbsolutePath();
                    String baseResourcesPath = new File(jarExportDir, "src" + File.separator + "main" + File.separator + "resources").getAbsolutePath();
                    String metaInfPath = new File(baseResourcesPath, "META-INF").getAbsolutePath();
                    
                    // 预创建基础目录
                    new File(baseJavaPath).mkdirs();
                    new File(baseResourcesPath).mkdirs();
                    new File(metaInfPath).mkdirs();
                    
                    // 添加到已创建目录缓存
                    createdDirs.add(baseJavaPath);
                    createdDirs.add(baseResourcesPath);
                    createdDirs.add(metaInfPath);
                    
                    // 并行导出Java文件
                    decompiledCodeMap.entrySet().parallelStream().forEach(entry -> {
                        try {
                            String className = entry.getKey();
                            String code = entry.getValue();
                            
                            // 将类名转换为文件路径，并添加src/main/java前缀
                            String filePath = "src" + File.separator + "main" + File.separator + "java" + File.separator + 
                                              className.replace('.', File.separatorChar) + ".java";
                            File outputFile = new File(jarExportDir, filePath);
                            
                            // 确保父目录存在（使用缓存避免重复创建）
                            String parentPath = outputFile.getParent();
                            if (parentPath != null && !createdDirs.contains(parentPath)) {
                                synchronized (createdDirs) {
                                    if (!createdDirs.contains(parentPath)) {
                                        Files.createDirectories(Paths.get(parentPath)); // 使用NIO创建目录
                                        createdDirs.add(parentPath);
                                    }
                                }
                            }
                            
                            // 使用NIO和直接缓冲区提高I/O效率
                            Files.write(outputFile.toPath(), code.getBytes(StandardCharsets.UTF_8));
                        } catch (Exception e) {
                            exportException.set(e);
                        } finally {
                            javaFilesLatch.countDown();
                        }
                    });
                    
                    // 并行导出非Java文件
                    nonJavaFilesMap.entrySet().parallelStream().forEach(entry -> {
                        try {
                            String fileName = entry.getKey();
                            String content = entry.getValue();
                            
                            // 确定文件应该放在哪个目录
                            String targetPath;
                            
                            // 特殊处理pom.xml文件，放在根目录与src同级
                            if (fileName.equals("pom.xml") || fileName.endsWith("/pom.xml") || fileName.endsWith("\\pom.xml")) {
                                targetPath = "pom.xml";
                            }
                            // 配置文件放在resources目录下
                            else if (fileName.endsWith(".xml") || fileName.endsWith(".properties") || 
                                fileName.endsWith(".yml") || fileName.endsWith(".yaml") || 
                                fileName.endsWith(".json") || fileName.endsWith(".txt") || 
                                fileName.endsWith(".MF")) {
                                
                                // 获取文件名（不含路径）
                                String simpleFileName = fileName;
                                int lastSlashIndex = Math.max(fileName.lastIndexOf('/'), fileName.lastIndexOf('\\'));
                                if (lastSlashIndex >= 0) {
                                    simpleFileName = fileName.substring(lastSlashIndex + 1);
                                }
                                
                                // 特殊处理META-INF目录下的文件，保持其在META-INF目录下
                                if (fileName.contains("META-INF")) {
                                    targetPath = "src" + File.separator + "main" + File.separator + "resources" + 
                                                 File.separator + "META-INF" + File.separator + simpleFileName;
                                } else {
                                    // 其他配置文件直接放在resources目录下
                                    targetPath = "src" + File.separator + "main" + File.separator + "resources" + 
                                                 File.separator + simpleFileName;
                                }
                            } else {
                                // 其他文件保持原有文件名，但放在resources目录下
                                String simpleFileName = fileName;
                                int lastSlashIndex = Math.max(fileName.lastIndexOf('/'), fileName.lastIndexOf('\\'));
                                if (lastSlashIndex >= 0) {
                                    simpleFileName = fileName.substring(lastSlashIndex + 1);
                                }
                                targetPath = "src" + File.separator + "main" + File.separator + "resources" + 
                                             File.separator + simpleFileName;
                            }
                            
                            File outputFile = new File(jarExportDir, targetPath);
                            
                            // 确保父目录存在（使用缓存避免重复创建）
                            String parentPath = outputFile.getParent();
                            if (parentPath != null && !createdDirs.contains(parentPath)) {
                                synchronized (createdDirs) {
                                    if (!createdDirs.contains(parentPath)) {
                                        Files.createDirectories(Paths.get(parentPath)); // 使用NIO创建目录
                                        createdDirs.add(parentPath);
                                    }
                                }
                            }
                            
                            // 使用NIO和直接缓冲区提高I/O效率
                            Files.write(outputFile.toPath(), content.getBytes(StandardCharsets.UTF_8));
                        } catch (Exception e) {
                            exportException.set(e);
                        } finally {
                            resourceFilesLatch.countDown();
                        }
                    });
                }).get(); // 等待所有任务完成
            } catch (InterruptedException | ExecutionException e) {
                throw new IOException("并行导出过程中出错", e);
            } finally {
                customThreadPool.shutdown();
            }
            
            // 等待所有导出任务完成
            try {
                javaFilesLatch.await(30, TimeUnit.SECONDS);
                resourceFilesLatch.await(30, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new IOException("导出过程被中断", e);
            }
            
            // 检查是否有异常发生
            if (exportException.get() != null) {
                throw exportException.get();
            }
            
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    
    /**
     * 解压JAR文件到指定目录
     * 使用并行处理和缓冲区优化提高解压效率
     * @param jarFile JAR文件
     * @param destDir 目标目录
     * @throws IOException 如果解压过程中发生I/O错误
     */
    private void extractJar(File jarFile, File destDir) throws IOException {
        try (JarFile jar = new JarFile(jarFile, false)) { // 添加false参数禁用ZIP文件验证，提高打开速度
            // 获取所有条目并转换为列表，以便并行处理
            List<JarEntry> entryList = Collections.list(jar.entries());
            
            // 创建目录缓存，避免重复创建目录
            Set<String> createdDirs = Collections.synchronizedSet(new HashSet<>(128)); // 预分配容量
            
            // 创建线程安全的非Java文件映射，避免同步块
            Map<String, String> localNonJavaFilesMap = new ConcurrentHashMap<>(64); // 预分配容量
            
            // 使用ForkJoinPool自定义并行度，避免过度并行
            int parallelism = Math.min(Runtime.getRuntime().availableProcessors(), 8);
            ForkJoinPool customThreadPool = new ForkJoinPool(parallelism);
            
            try {
                customThreadPool.submit(() -> {
                    entryList.parallelStream().forEach(entry -> {
                        try {
                            String entryName = entry.getName();
                            File entryFile = new File(destDir, entryName);
                            
                            // 如果是目录，创建目录
                            if (entry.isDirectory()) {
                                entryFile.mkdirs();
                                return;
                            }
                            
                            // 确保父目录存在（使用缓存避免重复创建）
                            String parentPath = entryFile.getParent();
                            if (parentPath != null && !createdDirs.contains(parentPath)) {
                                synchronized (createdDirs) {
                                    if (!createdDirs.contains(parentPath)) {
                                        new File(parentPath).mkdirs();
                                        createdDirs.add(parentPath);
                                    }
                                }
                            }
                            
                            // 使用NIO和直接缓冲区提高I/O效率
                            try (InputStream is = jar.getInputStream(entry);
                                 FileOutputStream fos = new FileOutputStream(entryFile)) {
                                
                                // 使用NIO通道进行高效传输
                                java.nio.channels.ReadableByteChannel inputChannel = 
                                    java.nio.channels.Channels.newChannel(is);
                                java.nio.channels.FileChannel outputChannel = fos.getChannel();
                                
                                // 使用transferFrom方法进行高效传输
                                outputChannel.transferFrom(inputChannel, 0, Long.MAX_VALUE);
                            }
                            
                            // 处理非Java文件，特别是pom.xml和其他XML文件
                            if (entryName.endsWith(".xml") || entryName.endsWith(".properties") || 
                                entryName.endsWith(".txt") || entryName.endsWith(".md") ||
                                entryName.endsWith(".MF") || entryName.endsWith(".yml") ||
                                entryName.endsWith(".yaml") || entryName.endsWith(".json")) {
                                try {
                                    // 使用NIO读取文件内容
                                    String content = new String(Files.readAllBytes(entryFile.toPath()), StandardCharsets.UTF_8);
                                    // 直接放入并发Map，避免同步块
                                    localNonJavaFilesMap.put(entryName, content);
                                } catch (Exception e) {
                                    System.err.println("Error reading file: " + entryName + ": " + e.getMessage());
                                }
                            }
                        } catch (Exception e) {
                            System.err.println("Error extracting entry: " + entry.getName() + ": " + e.getMessage());
                        }
                    });
                }).get(); // 等待所有任务完成
            } catch (InterruptedException | ExecutionException e) {
                throw new IOException("并行解压JAR文件时出错", e);
            } finally {
                customThreadPool.shutdown();
            }
            
            // 批量添加非Java文件到主映射
            nonJavaFilesMap.putAll(localNonJavaFilesMap);
        }
    }
    
    /**
     * 反编译指定目录下的所有class文件
     * 使用自定义线程池和批处理优化反编译效率
     * @param directory 包含class文件的目录
     * @throws IOException 如果反编译过程中发生I/O错误
     */
    private void decompileClasses(File directory) throws IOException {
        // 查找所有class文件，使用NIO快速遍历
        List<File> classFiles = Files.walk(directory.toPath())
                .filter(path -> path.toString().endsWith(".class"))
                .map(Path::toFile)
                .collect(Collectors.toList());
        
        // 创建CFR反编译器选项，优化反编译性能
        Map<String, String> options = new HashMap<>();
        options.put("showversion", "false");
        options.put("hideutf", "true");
        options.put("comments", "true");
        options.put("silent", "true");
        // 添加性能优化选项
        options.put("decodeenumswitch", "false"); // 禁用枚举switch解码，提高速度
        options.put("decodestringswitch", "false"); // 禁用字符串switch解码，提高速度
        options.put("sugarboxing", "false"); // 禁用自动装箱语法糖，提高速度
        options.put("decodelambdas", "false"); // 简化lambda解码，提高速度
        
        // 创建CFR输出接收器工厂
        OutputSinkFactory mySink = createOutputSinkFactory();
        
        // 使用自定义ForkJoinPool控制并行度
        int parallelism = Math.min(Runtime.getRuntime().availableProcessors(), 8);
        ForkJoinPool customThreadPool = new ForkJoinPool(parallelism);
        
        try {
            // 使用自定义线程池执行并行任务
            customThreadPool.submit(() -> {
                // 预热JIT编译器，提高后续反编译速度
                if (!classFiles.isEmpty()) {
                    try {
                        File firstClass = classFiles.get(0);
                        CfrDriver preDriver = new CfrDriver.Builder()
                            .withOutputSink(mySink)
                            .withOptions(options)
                            .build();
                        preDriver.analyse(Collections.singletonList(firstClass.getAbsolutePath()));
                    } catch (Exception e) {
                        // 忽略预热错误
                    }
                }
                
                // 使用并行流处理提高反编译效率
                classFiles.parallelStream().forEach(classFile -> {
                    try {
                        // 计算相对于临时目录的路径，用于确定包名
                        String relativePath = directory.toPath().relativize(classFile.toPath()).toString();
                        String className = relativePath.replace(File.separatorChar, '.');
                        
                        // 移除.class扩展名
                        if (className.endsWith(".class")) {
                            className = className.substring(0, className.length() - 6);
                        }
                        
                        // 检查缓存中是否已存在该类的反编译结果
                        if (decompileCache.containsKey(className)) {
                            String cachedCode = decompileCache.get(className);
                            decompiledCodeMap.put(className, cachedCode);
                            
                            // 从缓存的代码中提取类型信息
                            Map.Entry<String, JavaElementType> classInfo = extractClassInfo(cachedCode);
                            if (classInfo != null && classInfo.getValue() != null) {
                                elementTypeMap.put(className, classInfo.getValue());
                            }
                        } else {
                            // 执行反编译
                            CfrDriver driver = new CfrDriver.Builder()
                                .withOutputSink(mySink)
                                .withOptions(options)
                                .build();
                            driver.analyse(Collections.singletonList(classFile.getAbsolutePath()));
                        }
                    } catch (Exception e) {
                        System.err.println("Error decompiling " + classFile.getName() + ": " + e.getMessage());
                    }
                });
            }).get(); // 等待所有任务完成
        } catch (InterruptedException | ExecutionException e) {
            throw new IOException("并行反编译过程中出错", e);
        } finally {
            customThreadPool.shutdown();
        }
    }
    
    /**
     * 创建CFR输出接收器工厂
     * 优化了输出处理逻辑，提高反编译效率
     * @return 输出接收器工厂实例
     */
    private OutputSinkFactory createOutputSinkFactory() {
        return new OutputSinkFactory() {
            // 使用线程本地变量存储临时结果，避免线程间干扰
            private final ThreadLocal<StringBuilder> resultBuilder = ThreadLocal.withInitial(StringBuilder::new);
            
            @Override
            public List<SinkClass> getSupportedSinks(SinkType sinkType, Collection<SinkClass> collection) {
                return Collections.singletonList(SinkClass.STRING);
            }

            @Override
            public <T> Sink<T> getSink(SinkType sinkType, SinkClass sinkClass) {
                return new Sink<T>() {
                    @Override
                    public void write(T t) {
                        // 只处理反编译后的Java代码
                        if (sinkType == SinkType.JAVA && t instanceof String) {
                            String result = (String) t;
                            
                            // 使用预分配的StringBuilder提高字符串处理效率
                            StringBuilder builder = resultBuilder.get();
                            builder.setLength(0); // 清空重用
                            builder.append(result);
                            
                            // 从反编译结果中提取类名和类型
                            Map.Entry<String, JavaElementType> classInfo = extractClassInfo(result);
                            if (classInfo != null && classInfo.getKey() != null) {
                                String className = classInfo.getKey();
                                JavaElementType elementType = classInfo.getValue();
                                
                                // 批量更新映射，减少锁竞争
                                decompiledCodeMap.put(className, result);
                                elementTypeMap.put(className, elementType);
                                
                                // 同时更新缓存，避免重复反编译
                                decompileCache.putIfAbsent(className, result);
                            }
                        }
                    }
                };
            }
        };
    }
    
    // 缓存提取的类信息，避免重复解析
    private final Map<String, Map.Entry<String, JavaElementType>> classInfoCache = new ConcurrentHashMap<>();
    
    // 预编译正则表达式，提高匹配效率
    private static final java.util.regex.Pattern PACKAGE_PATTERN = 
        java.util.regex.Pattern.compile("package\\s+([\\w\\.]+)\\s*;");
    private static final java.util.regex.Pattern CLASS_PATTERN = 
        java.util.regex.Pattern.compile("(public|private|protected)?\\s*(abstract|final)?\\s*class\\s+([\\w]+)[<{\\s].*");
    private static final java.util.regex.Pattern INTERFACE_PATTERN = 
        java.util.regex.Pattern.compile("(public|private|protected)?\\s*interface\\s+([\\w]+)[<{\\s].*");
    private static final java.util.regex.Pattern ENUM_PATTERN = 
        java.util.regex.Pattern.compile("(public|private|protected)?\\s*enum\\s+([\\w]+)[<{\\s].*");
    
    /**
     * 从反编译代码中提取类名和类型
     * 使用正则表达式和缓存机制优化性能
     * @param code 反编译代码
     * @return 包含类名和类型的Map.Entry
     */
    private Map.Entry<String, JavaElementType> extractClassInfo(String code) {
        // 使用代码的哈希值作为缓存键
        int codeHash = code.hashCode();
        String cacheKey = String.valueOf(codeHash);
        
        // 检查缓存中是否已存在该代码的解析结果
        if (classInfoCache.containsKey(cacheKey)) {
            return classInfoCache.get(cacheKey);
        }
        
        // 查找package和class/interface/enum声明
        String packageName = "";
        String className = null;
        JavaElementType elementType = JavaElementType.UNKNOWN;
        
        // 使用正则表达式提取包名
        java.util.regex.Matcher packageMatcher = PACKAGE_PATTERN.matcher(code);
        if (packageMatcher.find()) {
            packageName = packageMatcher.group(1);
        }
        
        // 使用正则表达式提取类名和类型
        java.util.regex.Matcher classMatcher = CLASS_PATTERN.matcher(code);
        if (classMatcher.find()) {
            className = classMatcher.group(3);
            elementType = JavaElementType.CLASS;
        } else {
            java.util.regex.Matcher interfaceMatcher = INTERFACE_PATTERN.matcher(code);
            if (interfaceMatcher.find()) {
                className = interfaceMatcher.group(2);
                elementType = JavaElementType.INTERFACE;
            } else {
                java.util.regex.Matcher enumMatcher = ENUM_PATTERN.matcher(code);
                if (enumMatcher.find()) {
                    className = enumMatcher.group(2);
                    elementType = JavaElementType.ENUM;
                }
            }
        }
        
        // 组合包名和类名
        Map.Entry<String, JavaElementType> result = null;
        if (className != null) {
            final String fullClassName = packageName.isEmpty() ? className : packageName + "." + className;
            result = new AbstractMap.SimpleEntry<>(fullClassName, elementType);
            
            // 将结果存入缓存
            classInfoCache.put(cacheKey, result);
        }
        
        return result;
    }
}